home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / gus / vts139b.zip / SOUNDDEV.PAS < prev    next >
Pascal/Delphi Source File  |  1993-10-10  |  26KB  |  764 lines

  1. {****************************************************************************}
  2. {                                                                            }
  3. { MODULE:         SoundDevices                                               }
  4. {                                                                            }
  5. { DESCRIPTION:    Implements a common interface to access the different      }
  6. {                 sampled audio devices possible on a PC, wether they work   }
  7. {                 with DMA or polling.                                       }
  8. {                                                                            }
  9. { AUTHOR:         Juan Carlos Arévalo Baeza                                  }
  10. {                                                                            }
  11. { MODIFICATIONS:  Nobody yet.                                                }
  12. {                                                                            }
  13. { HISTORY:        xx-May-1992 Conception.                                    }
  14. {                 xx-Jun-1992 Development.                                   }
  15. {                 21-Jul-1992 Documentation (this mess).                     }
  16. {                 07-Oct-1992 Redo from start :-( (DMA Affairs).             }
  17. {                                                                            }
  18. { (C) 1992 VangeliSTeam                                                      }
  19. {____________________________________________________________________________}
  20.  
  21. UNIT SoundDevices;
  22.  
  23. INTERFACE
  24.  
  25. USES {SongElements, }Hardware;
  26.  
  27.  
  28.  
  29. {----------------------------------------------------------------------------}
  30. { Device configuration definitions.                                          }
  31. {____________________________________________________________________________}
  32.  
  33. TYPE
  34.   TDevName = STRING[50];                    { Name/description of device.                                    }
  35.   TDevID   = STRING[20];                    { Device identification string.                                  }
  36.  
  37.   TProc            = PROCEDURE;                       { Generic procedure without parameters.                }
  38.   TNameProc        = FUNCTION             : TDevName; { Procedure that returns the name of a device.         }
  39.   TInitDevProc     = PROCEDURE (Hz: WORD);            { Device initialisation procedure.                     }
  40.   TChgHzProc       = PROCEDURE (Hz: WORD);            { Sample rate change procedure.                        }
  41.   TGetRealFreqProc = FUNCTION  (Hz: WORD) : WORD;     { Returns the real sampling freq. when Hz is selected. }
  42.   TDetectProc      = FUNCTION             : BOOLEAN;  { Device autodetection procedure.                      }
  43.  
  44. TYPE
  45.   PSoundDevice = ^TSoundDevice;   { Device record for including in a linked list.                            }
  46.   TSoundDevice = RECORD
  47.     DevID         : TDevID;       { Device ID string.                                                        }
  48.     DMA           : BOOLEAN;      { TRUE if the device uses DMA output (shouldn't be needed).                }
  49.  
  50.     Name            : TNameProc;        { Device name.                                                       }
  51.     Autodetect      : TDetectProc;      { Autodetection procedure.                                           }
  52.     InitRut         : TInitDevProc;     { Initialisation procedure.                                          }
  53.     ChgHzProc       : TChgHzProc;       { Sample rate change procedure.                                      }
  54.     GetRealFreqProc : TGetRealFreqProc; { Real sampling freq.                                                }
  55.     TimerHandler,
  56.     PollRut         : TProc;            { Routine to be executed for active polling (hand made).             }
  57.     EndRut          : TProc;            { Device closing procedure.                                          }
  58.  
  59.     Next          : PSoundDevice;     { Next record in the list.                                             }
  60.   END;
  61.  
  62. CONST
  63.   NumDevices   : BYTE         = 0;   { Count of the number of installed devices.    }
  64.   ActiveDevice : PSoundDevice = NIL; { Device being used right now.                 }
  65.  
  66.  
  67.  
  68.  
  69. {----------------------------------------------------------------------------}
  70. { Device Stack.                                                              }
  71. {____________________________________________________________________________}
  72.  
  73. CONST
  74.   DevStkSize = 1000;
  75. VAR
  76.   DevStack : ARRAY[1..DevStkSize] OF BYTE;
  77.   DevSS    : WORD;
  78.   DevSP    : WORD;
  79.  
  80. {----------------------------------------------------------------------------}
  81. { Sample buffers definition.                                                 }
  82. {____________________________________________________________________________}
  83.  
  84. TYPE
  85.   TDataType = (dtShortInt, dtInteger);        { Data type of the samples. }
  86.  
  87.   TIntBuff   = ARRAY[0..32760] OF INTEGER;    { Data types for big arrays. }
  88.   TShortBuff = ARRAY[0..65520] OF SHORTINT;
  89.  
  90.   PIntBuff   = ^TIntBuff;                     { Idem. }
  91.   PShortBuff = ^TShortBuff;
  92.  
  93.   PSampleBuffer = ^TSampleBuffer;   { PCM Buffer. }
  94.   TSampleBuffer = RECORD
  95.     InUse    : BOOLEAN;             { TRUE while it's being used by the device.       }
  96.     NSamples,                       { Size of the buffer in samples.                  }
  97.     RateHz   : WORD;                { Sampling frequency.                             }
  98.     Channels : BYTE;                { 1 or 4, channels contained in the buffer.       }
  99.     CASE DataType : TDataType OF
  100.       dtInteger:  ( IData : PIntBuff );   { Pointer to the buffer.                    }
  101.       dtShortInt: ( SData : PShortBuff );
  102.   END;
  103.  
  104. CONST
  105.   MaxChannels     = 32;
  106.   Sounding     : POINTER = NIL;  { Buffer that is actually sounding (NON-DMA only). }
  107.   SoundLeft    : WORD    = 0;    { Number of samples left in the buffer.            }
  108.   NumChannels  : WORD    = 1;    { Number of channels in the buffer.                }
  109.   ChannelIncr  : WORD    = 1;    { Size of one sample in the buffer.                }
  110.  
  111.  
  112.  
  113.  
  114. {----------------------------------------------------------------------------}
  115. { DMA buffers definition.                                                    }
  116. {____________________________________________________________________________}
  117.  
  118. CONST
  119.   DMABufferSize = 4096;      { Size of the buffer. }
  120.  
  121. VAR
  122.   DMABufferPtr : POINTER;                         { Pointers for the }
  123.   DMABuffer    : POINTER;                         { DMA buffer.      }
  124.   DMABufferEnd : WORD;
  125.  
  126.   DMABufferYet : BOOLEAN;
  127.  
  128. CONST
  129.   FinalBufferSize = 4096;
  130.   FinalBufferPos  : WORD = 0;
  131.  
  132. VAR
  133.   FinalBuffer : ARRAY[0..FinalBufferSize-1] OF INTEGER;
  134.  
  135.  
  136.  
  137.  
  138. {----------------------------------------------------------------------------}
  139. { Hardware parameters.                                                       }
  140. {____________________________________________________________________________}
  141.  
  142. CONST
  143.   DefaultHz                   = 16000;     { Default sampling rate.                                }
  144.   DeviceIdling      : BOOLEAN = TRUE;      { TRUE if there are no samples sounding.                }
  145.   TimerHz           : WORD    = DefaultHz; { Clock frequency of the INT 8 timer.                   }
  146.   LastHz            : WORD    = 0;         { Older INT 8 frequency (for detecting change).         }
  147.   SoundHz           : WORD    = DefaultHz; { Sampling frequency of the sound.                      }
  148.   DesiredHz         : WORD    = DefaultHz; { Desired sampling frequency of the sound.              }
  149.   SystemClockCount  : WORD    = 0;         { Clock count for calling the original INT 8.           }
  150.   SystemClockIncr   : WORD    = 0;         { Increment for calling the original INT 8.             }
  151.   TimerVal          : WORD    = 0;         { Value given to the INT 8 timer.                       }
  152.   DeviceInitialized : BOOLEAN = FALSE;     { TRUE if a device has already been initialized.        }
  153.   DMAOffset         : WORD    = 1;         { Number of samples to discard in DMA transferences.    }
  154.   HzChanged         : BOOLEAN = FALSE;
  155.   DoBassPower       : BOOLEAN = FALSE;
  156.   MixMethod         : BYTE    = 3;         { Mono/stereo mixing algorithm.                         }
  157.   Stereo            : BOOLEAN = FALSE;
  158.   BytesPerSample    : BYTE    = 1;
  159.   DevBits           : BYTE    = 8;
  160.   DMAStop           : BOOLEAN = FALSE;
  161.   DMAStopped        : BOOLEAN = FALSE;
  162.   DMAIrqWatch       : BYTE    = 0;
  163.   DMAChannel        : WORD    = 0;
  164.   UsingGUS          : BOOLEAN = FALSE;
  165.   TicksPerSecond    : WORD    = 50;     { Number of ticks per second, 50 = Europe, 60 = USA.    }
  166.  
  167.   TrebleFilterVal_Left   : WORD =  6;
  168.   TrebleFilterMult_Left  : WORD =  3;
  169.   BassFilterVal_Left     : WORD = 13;
  170.   BassFilterMult_Left    : WORD =  0;
  171.   TrebleFilterVal_Right  : WORD =  6;
  172.   TrebleFilterMult_Right : WORD =  3;
  173.   BassFilterVal_Right    : WORD = 13;
  174.   BassFilterMult_Right   : WORD =  0;
  175.  
  176.  
  177.  
  178. {----------------------------------------------------------------------------}
  179. { Periodic process.                                                          }
  180. {____________________________________________________________________________}
  181.  
  182. VAR
  183.   PeriodicProc  : TProc;    { Periodic process (normally a music interpreter).           }
  184.  
  185. CONST
  186.   PeriodicHz    : BYTE = 0; { Frequency for calling the periodic process.                }
  187.   PeriodicStart : WORD = 1; { Countdown starting point (NON-DMA only).                   }
  188.   PeriodicCount : WORD = 0; { Countdown.               (idem).                           }
  189.  
  190.  
  191.  
  192.  
  193. {----------------------------------------------------------------------------}
  194. { Buffer provider definitions.                                               }
  195. {____________________________________________________________________________}
  196.  
  197. TYPE
  198.   TAskBufferProc = FUNCTION : PSampleBuffer; { Buffer provider function. }
  199.  
  200. VAR
  201.   AskBufferProc  : TAskBufferProc; { Pointer to the buffer provider.             }
  202.   ActualBuffer,                    { Buffer being used.                          }
  203.   NextBuffer     : PSampleBuffer;  { Buffer that will be used next.              }
  204.   PleaseFallback : WORD{BOOLEAN};        { Set TRUE if there are no buffers available. }
  205.  
  206.  
  207.  
  208.  
  209. {----------------------------------------------------------------------------}
  210. { Sound Blaster device variables.                                            }
  211. {____________________________________________________________________________}
  212.  
  213. CONST
  214.   DSPWritePort : WORD    = 0;
  215.   DSP8AckPort  : WORD    = 0;
  216.   DSPLifePort  : WORD    = 0;
  217.   SbCmdTimeout : WORD    = 100;   { $10 DSP Command timeout.   }
  218.   SbSplTimeout : WORD    = 10;    { $10 DSP Parameter timeout. }
  219.  
  220.  
  221.  
  222.  
  223. {----------------------------------------------------------------------------}
  224. { DAC device ports.                                                          }
  225. {____________________________________________________________________________}
  226.  
  227. CONST
  228.   DacPort  : WORD = $378;
  229.   LDacPort : WORD = $378;
  230.   RDacPort : WORD = $378;
  231.  
  232.  
  233.  
  234.  
  235.  
  236. {----------------------------------------------------------------------------}
  237. { Functions in the ASM portion.                                              }
  238. {____________________________________________________________________________}
  239.  
  240. CONST
  241.   DeviceStartRut   : WORD = 0;
  242.   DeviceRut1       : WORD = 0;
  243.   DeviceRut2       : WORD = 0;
  244.   DeviceKickRut    : WORD = 0;
  245.   DeviceFillRut    : WORD = 0;
  246.  
  247. PROCEDURE MixChannels;
  248. {PROCEDURE DumpSamples;}
  249. PROCEDURE DMAFillBuffer;
  250. PROCEDURE DMADoGetBuff;
  251. PROCEDURE NullTimerHandler;
  252. PROCEDURE TimerHandler;
  253. PROCEDURE DMATimerHandler;
  254.  
  255. PROCEDURE DevInitSbNonDMA(Ster: BOOLEAN; Bits: BYTE);
  256. PROCEDURE DevInitSbDMA   (Ster: BOOLEAN; Bits: BYTE);
  257. PROCEDURE DevInitSpkr    (Ster: BOOLEAN; Bits: BYTE);
  258. PROCEDURE DevInitDac     (Ster: BOOLEAN; Bits: BYTE);
  259.  
  260.  
  261.  
  262.  
  263. {----------------------------------------------------------------------------}
  264. { Functions to be used by devices only.                                      }
  265. {____________________________________________________________________________}
  266.  
  267. FUNCTION  InitDevice   (Device: PSoundDevice) : WORD; { Used to declare a device.                            }
  268. PROCEDURE PollDevice;                                 { Used to manually poll the device, if it is required. }
  269. PROCEDURE CalcTimerData(Hz: WORD);                    { Used to calculate the different Hz variables.        }
  270. PROCEDURE DefaultChgHz (Hz: WORD);                    { Used as a default TChgHzProc.                        }
  271. FUNCTION  GetRealFreq  (Hz: WORD)             : WORD; { Used as a default TRealFreqProc.                     }
  272. PROCEDURE InitTimer;                                  { Used to reinitialise the timer after a freq. change. }
  273. FUNCTION  DoGetBuffer                         : WORD; { Used to get the next buffer prepared.                }
  274.  
  275.  
  276.  
  277.  
  278. {----------------------------------------------------------------------------}
  279. { Functions to be used by the sound generators only.                         }
  280. {____________________________________________________________________________}
  281.  
  282. PROCEDURE SetDevice      (p: PSoundDevice);                             { Used to initialise a buffer for output.  }
  283. FUNCTION  IndexDevice    (i: WORD)                      : PSoundDevice; { Used to index the devices.               }
  284. FUNCTION  LocateDevice   (ID: STRING)                   : PSoundDevice; { Used to find a given device.             }
  285. PROCEDURE SetPeriodicProc(Proc: TProc; PerSecond: WORD);                { Used to initialise the periodic process. }
  286. PROCEDURE SetBufferAsker (Proc: TAskBufferProc);                        { Used to initialise the buffer asker.     }
  287. PROCEDURE StartSampling;                                                { Used to start the sound output.          }
  288. PROCEDURE EndSampling;                                                  { Used to end the sound output.            }
  289.  
  290.  
  291. PROCEDURE InitSoundDevices;
  292.  
  293.  
  294.  
  295.  
  296. IMPLEMENTATION
  297.  
  298. USES Dos,
  299.      Debugging, Output43;
  300.  
  301.  
  302.  
  303.  
  304. {----------------------------------------------------------------------------}
  305. { Internal data.                                                             }
  306. {____________________________________________________________________________}
  307.  
  308. CONST
  309.   DeviceList       : PSoundDevice = NIL;   { Linked list of all devices.                     }
  310.   OldTimerHandler  : POINTER      = NIL;   { Pointer to the original INT 8.                  }
  311.   IntInstalled     : BOOLEAN      = FALSE; { TRUE if the INT 8 handler is already installed. }
  312.  
  313.  
  314.  
  315.  
  316. {----------------------------------------------------------------------------}
  317. { Null procedures used in the unit.                                          }
  318. {____________________________________________________________________________}
  319.  
  320. PROCEDURE NullProcedure;                  FAR; ASSEMBLER; ASM END;
  321. FUNCTION  NullBufferProc : PSampleBuffer; FAR; BEGIN NullBufferProc := NIL; END;
  322.  
  323.  
  324. PROCEDURE NullInt; ASSEMBLER;
  325.   ASM
  326.         PUSH    AX
  327.         MOV     AL,$20
  328.         OUT     $20,AL
  329.         POP     AX
  330.         IRET
  331.   END;
  332.  
  333.  
  334.  
  335.  
  336. {----------------------------------------------------------------------------}
  337. { Periodic process implementation.                                           }
  338. {____________________________________________________________________________}
  339.  
  340. PROCEDURE InitPeriodic;
  341.   BEGIN
  342.     IF PeriodicHz = 0 THEN BEGIN
  343.       PeriodicStart   := 0;
  344.       PeriodicCount   := 0;
  345.       SystemClockIncr := TimerVal;
  346.     END ELSE BEGIN
  347.       PeriodicStart := TimerHz DIV PeriodicHz;
  348.       IF PeriodicStart = 0 THEN PeriodicStart := 1;
  349.       PeriodicCount := 1;
  350.       SystemClockIncr := TimerVal {* PeriodicStart};
  351.     END;
  352.   END;
  353.  
  354.  
  355. PROCEDURE SetPeriodicProc(Proc: TProc; PerSecond: WORD);
  356.   BEGIN
  357.     ASM
  358.         PUSHF
  359.         CLI
  360.         LES     BX,[Proc]
  361.         MOV     WORD PTR [PeriodicProc],BX;
  362.         MOV     WORD PTR [PeriodicProc+2],ES;
  363.         POPF
  364.     END;
  365.     PeriodicHz   := PerSecond;
  366.     InitPeriodic;
  367.   END;
  368.  
  369.  
  370.  
  371.  
  372. {----------------------------------------------------------------------------}
  373. { Hardware and interrupt handling procedures.                                }
  374. {____________________________________________________________________________}
  375.  
  376. PROCEDURE OriginalHwTimer; ASSEMBLER;
  377.   ASM
  378.         MOV     AL,54       { Selct timer 0, secuential access and contínuous mode. }
  379.         OUT     43h,AL
  380.         XOR     AL,AL       { Set the counter to 0 (65536). }
  381.         OUT     40h,AL      { Lower byte of the counter.    }
  382.         OUT     40h,AL      { Higher byte.                  }
  383.   END;
  384.  
  385.  
  386. PROCEDURE SetHwTimer(value: WORD); ASSEMBLER;
  387.   ASM
  388.         MOV     AL,54       { Selct timer 0, secuential access and contínuous mode. }
  389.         OUT     43h,AL
  390.         MOV     AX,value
  391.         OUT     40h,AL      { Lower byte of the counter.    }
  392.         XCHG    AH,AL
  393.         OUT     40h,AL      { Higher byte.                  }
  394.   END;
  395.  
  396.  
  397. PROCEDURE RestoreTimer;
  398.   BEGIN
  399.     IF IntInstalled THEN
  400.       BEGIN
  401.         SetIntVec(8, OldTimerhandler);
  402.         OriginalHwTimer;
  403.         IntInstalled := FALSE;
  404.       END;
  405.   END;
  406.  
  407.  
  408. PROCEDURE InitTimer;
  409.   BEGIN
  410.     InitPeriodic;
  411.  
  412.     IF NOT IntInstalled THEN
  413.       BEGIN
  414.         IntInstalled := TRUE;
  415.         GetIntVec(8, OldTimerHandler);
  416.         SetIntVec(8, @ActiveDevice^.TimerHandler);
  417.       END;
  418.  
  419. {    SetHwTimer(2980);}
  420.     SetHwTimer(TimerVal);
  421.   END;
  422.  
  423.  
  424.  
  425.  
  426. {----------------------------------------------------------------------------}
  427. { Procedures exported for the sound generator.                               }
  428. {____________________________________________________________________________}
  429.  
  430. PROCEDURE StartSampling;
  431.   BEGIN
  432.     IF NOT DeviceInitialized THEN RestoreTimer;
  433.  
  434.     ActualBuffer      := NIL;
  435.     NextBuffer        := NIL;
  436.     SoundLeft         := 0;
  437.     PleaseFallBack    := 0;
  438.     DeviceIdling      := TRUE;
  439.     DMABufferPtr      := DMABuffer;
  440.     DMABufferYet      := TRUE;
  441.     Stereo            := FALSE;
  442.     DevBits           := 8;
  443.     BytesPerSample    := 1;
  444.  
  445.     FillChar(DMABuffer^, DMABufferSize, $80);
  446.  
  447.     IF (ActiveDevice <> NIL) {AND (NOT DeviceInitialized)} THEN
  448.       BEGIN
  449.         ASM CLI END;
  450.  
  451.         DeviceInitialized := TRUE;
  452.  
  453.         ActiveDevice^.InitRut(DesiredHz);
  454.  
  455.         ASM STI END;
  456.       END;
  457.  
  458.     BytesPerSample := (DevBits + 7) DIV 8 *  (BYTE(Stereo) + 1);
  459.   END;
  460.  
  461.  
  462. PROCEDURE EndSampling;
  463.   BEGIN
  464.     IF (ActiveDevice <> NIL) AND DeviceInitialized THEN
  465.       BEGIN
  466.         ASM CLI END;
  467.         FillChar(DMABuffer^, DMABufferSize, $80);
  468.         ActiveDevice^.EndRut;
  469.         RestoreTimer;
  470.         ASM STI END;
  471.         DeviceInitialized := FALSE;
  472.       END;
  473.   END;
  474.  
  475.  
  476. PROCEDURE SetBufferAsker (Proc: TAskBufferProc);
  477.   BEGIN
  478.     ASM CLI END;
  479.      AskBufferProc := Proc;
  480.     ASM STI END;
  481.   END;
  482.  
  483.  
  484. PROCEDURE SetDevice(p: PSoundDevice);
  485.   BEGIN
  486.     IF p <> NIL THEN
  487.       BEGIN
  488.         IF DeviceInitialized THEN
  489.           BEGIN
  490.             EndSampling;
  491.             ActiveDevice := p;
  492.             StartSampling;
  493.           END
  494.         ELSE
  495.           ActiveDevice := p;
  496.       END;
  497.   END;
  498.  
  499.  
  500. FUNCTION LocateDevice(ID: STRING) : PSoundDevice;
  501.  
  502.   FUNCTION NotInStr(VAR s, ss: STRING) : BOOLEAN;
  503.     VAR
  504.       i : WORD;
  505.     BEGIN
  506.       NotInStr := TRUE;
  507.       IF Length(ss) > Length(s) THEN EXIT;
  508.       FOR i := 1 TO Length(ss) DO
  509.         IF UpCase(s[i]) <> UpCase(ss[i]) THEN EXIT;
  510.       NotInStr := FALSE;
  511.     END;
  512.  
  513.   VAR
  514.     p : PSoundDevice;
  515.   BEGIN
  516.     p := DeviceList;
  517.     WHILE (p <> NIL) AND NotInStr(p^.DevID, ID) DO p := p^.Next;
  518.     LocateDevice := p;
  519.   END;
  520.  
  521.  
  522. FUNCTION IndexDevice(i: WORD) : PSoundDevice;
  523.   VAR
  524.     p : PSoundDevice;
  525.   BEGIN
  526.     p := DeviceList;
  527.     DEC(i);
  528.     WHILE (p <> NIL) AND (i > 0) DO
  529.       BEGIN
  530.         p := p^.Next;
  531.         DEC(i);
  532.       END;
  533.  
  534.     IndexDevice := p;
  535.   END;
  536.  
  537.  
  538.  
  539.  
  540. {----------------------------------------------------------------------------}
  541. { Implementation of some procedures exported to the device controllers.       }
  542. {____________________________________________________________________________}
  543.  
  544. FUNCTION InitDevice(Device: PSoundDevice) : WORD;
  545.   BEGIN
  546.     Device^.Next := DeviceList;
  547.     DeviceList   := Device;
  548.     IF ActiveDevice = NIL THEN SetDevice(Device);
  549.     INC(NumDevices);
  550.   END;
  551.  
  552.  
  553. PROCEDURE PollDevice;
  554.   BEGIN
  555.     ActiveDevice^.PollRut;
  556.   END;
  557.  
  558.  
  559. FUNCTION GetRealFreq(Hz: WORD) : WORD;
  560.   VAR
  561.     i    : WORD;
  562.     NHz1 : WORD;
  563.     NHz2 : WORD;
  564.   BEGIN
  565.     IF Hz = 0 THEN Hz := 1;
  566.     i := 1193180 DIV Hz;
  567.  
  568.     NHz1 := 1193180 DIV  i;
  569.     NHz2 := 1193180 DIV (i + 1);
  570.     IF ABS(INTEGER(NHz1 - Hz)) > ABS(INTEGER(NHz2 - Hz)) THEN NHz1 := NHz2;
  571.  
  572.     GetRealFreq := NHz1;
  573.   END;
  574.  
  575.  
  576. PROCEDURE CalcTimerData(Hz: WORD);
  577.   BEGIN
  578.     Hz := GetRealFreq(Hz);
  579.  
  580.     IF Hz = 0 THEN TimerVal := $FFFF
  581.               ELSE TimerVal := 1193180 DIV Hz;
  582.  
  583.     TimerHz         := 1193180 DIV TimerVal;
  584.     SoundHz         := TimerHz;
  585. {    SystemClockIncr := TimerVal;}
  586.   END;
  587.  
  588.  
  589. PROCEDURE DefaultChgHz(Hz: WORD);
  590.   BEGIN
  591.     CalcTimerData(Hz);
  592.     InitTimer;
  593.   END;
  594.  
  595.  
  596. FUNCTION DoGetBuffer : WORD;
  597.   CONST
  598.     Semaphore : BYTE    = 0;
  599.     Size      : WORD    = 1;
  600.   BEGIN
  601.     DoGetBuffer := 0;
  602.     IF Semaphore > 0 THEN EXIT;
  603.     INC(Semaphore);
  604.  
  605.     IF ActualBuffer <> NIL THEN
  606.       BEGIN
  607.         Size := ActualBuffer^.NSamples;
  608.         ActualBuffer^.InUse := FALSE; { It must be already finished using. }
  609.       END;
  610.  
  611.     ActualBuffer := NextBuffer;
  612.  
  613.     IF ActualBuffer = NIL THEN BEGIN     { If there had not been next buffer before. }
  614.       ActualBuffer := AskBufferProc;
  615.       IF ActualBuffer <> NIL THEN BEGIN  { If there has just been one more buffer. }
  616.         ActualBuffer^.InUse := TRUE;
  617.       END;
  618.     END;
  619.  
  620.     IF ActualBuffer = NIL THEN
  621.       BEGIN                                  { If there is no buffer :-( }
  622.         IF (Size <> 1) AND (NOT ActiveDevice^.DMA) THEN
  623.           INC(PleaseFallBack);
  624.         SoundLeft      := 0;
  625.         IF NOT ActiveDevice^.DMA THEN
  626.           BEGIN
  627.             PeriodicCount := 1;
  628.             LastHz        := PeriodicHz;
  629.             ActiveDevice^.ChgHzProc(LastHz);
  630.           END;
  631.       END
  632.     ELSE
  633.       BEGIN
  634.         Sounding     := ActualBuffer^.IData;
  635.         SoundLeft    := ActualBuffer^.NSamples;
  636.         NumChannels  := ActualBuffer^.Channels;
  637.         ChannelIncr  := ActualBuffer^.Channels * (ORD(ActualBuffer^.DataType)+1);
  638.  
  639.         IF (LastHz <> ActualBuffer^.RateHz) THEN BEGIN
  640.           LastHz := ActualBuffer^.RateHz;
  641.           ActiveDevice^.ChgHzProc(LastHz);
  642.  
  643.           HzChanged := TRUE;
  644.  
  645.         END;
  646.  
  647.         IF ActiveDevice^.DMA THEN
  648.           BEGIN
  649.             IF SoundLeft > DMAOffset + 5 THEN
  650.               DEC(SoundLeft, DMAOffset)
  651.             ELSE
  652.               SoundLeft := 5;
  653.           END;
  654.  
  655.         NextBuffer   := AskBufferProc; { Get the buffer, if there is one. }
  656.         IF NextBuffer <> NIL THEN
  657.           NextBuffer^.InUse := TRUE;
  658.  
  659.  
  660.       END;
  661.  
  662.     DoGetBuffer := SoundLeft;
  663.  
  664. {
  665.     WriteNum(40, SoundLeft, $70);
  666. }
  667.  
  668.     DEC(Semaphore);
  669.   END;
  670.  
  671.  
  672.  
  673.  
  674. {----------------------------------------------------------------------------}
  675. { Unit initialisation.                                                       }
  676. {____________________________________________________________________________}
  677.  
  678. PROCEDURE InitSoundDevices;
  679.   TYPE
  680.     PFreeBlock = ^TFreeBlock;
  681.     TFreeBlock =
  682.       RECORD
  683.         Next : PFreeBlock;
  684.         Size : POINTER;
  685.       END;
  686.   VAR
  687.     l        : LONGINT;
  688.     PtrFree  : POINTER;
  689.     OldHPtr  : POINTER;
  690.     p        : PFreeBlock;
  691.     OffsFree : WORD;
  692.   BEGIN
  693.  
  694.     PeriodicProc  := NullProcedure;
  695.     AskBufferProc := NullBufferProc;
  696.  
  697.     { Calc. for the DMA buffers. This messes with the heap, but works. }
  698.  
  699.     DMABuffer := HeapPtr;
  700.  
  701.     l := (LONGINT(SEG(DMABuffer^)) SHL 4) + OFS(DMABuffer^); { l = linear address. }
  702.  
  703.     PtrFree  := HeapPtr;
  704.     OffsFree := 0;
  705.  
  706.     IF LONGINT(WORD(l)) + DMABufferSize > 65536 THEN { If address doesn't match,    }
  707.       BEGIN                                          { get an address that matches  }
  708.         OffsFree := 65536 - LONGINT(WORD(l));        { by incrementing to a 64 Kb   }
  709.         l := (l AND $F0000) + $10000;                { boundary.                    }
  710.       END;
  711.  
  712.     DMABuffer    := Ptr((l SHR 4)  AND $F000, WORD(l));
  713.     DMABufferPtr := DMABuffer;
  714.     DMABufferEnd := OFS(DMABuffer^) + DMABufferSize;
  715.  
  716.     OldHPtr      := HeapPtr;
  717.     HeapPtr      := Ptr((l + DMABufferSize + 16) SHR 4, 0); { Manually, allocate the }
  718.     IF OldHPtr = FreeList THEN                              { buffer.                }
  719.       BEGIN
  720.         FreeList   := HeapPtr;
  721.       END
  722.     ELSE
  723.       BEGIN
  724.         p := FreeList;
  725.         WHILE p^.Next <> OldHPtr DO
  726.           p := p^.Next;
  727.         p^.Next := HeapPtr;
  728.       END;
  729.  
  730.     FillChar(HeapPtr^, 8, 0); { Clear the Heap Pointer contents. }
  731.  
  732.     IF OffsFree > 0 THEN              { Update the Heap by freeing  }
  733.       FreeMem(PtrFree, OffsFree);     { manually the unused memory. }
  734.   END;
  735.  
  736.  
  737.  
  738.  
  739. FUNCTION GetDMACount : WORD;
  740.   BEGIN
  741.     GetDMACount := Hardware.GetDMACount(DMAChannel);
  742.   END;
  743.  
  744. {$L SOUNDDEV}
  745.  
  746. PROCEDURE MixChannels;                                EXTERNAL;
  747. {PROCEDURE DumpSamples;                                EXTERNAL;}
  748. PROCEDURE DMAFillBuffer;                              EXTERNAL;
  749. PROCEDURE DMADoGetBuff;                               EXTERNAL;
  750. PROCEDURE NullTimerHandler;                           EXTERNAL;
  751. PROCEDURE TimerHandler;                               EXTERNAL;
  752. PROCEDURE DMATimerHandler;                            EXTERNAL;
  753.                                                       
  754. PROCEDURE DevInitSbNonDMA(Ster: BOOLEAN; Bits: BYTE); EXTERNAL;
  755. PROCEDURE DevInitSbDMA   (Ster: BOOLEAN; Bits: BYTE); EXTERNAL;
  756. PROCEDURE DevInitSpkr    (Ster: BOOLEAN; Bits: BYTE); EXTERNAL;
  757. PROCEDURE DevInitDac     (Ster: BOOLEAN; Bits: BYTE); EXTERNAL;
  758.  
  759.  
  760.  
  761.  
  762. END.
  763.  
  764.